package org.hrqing.chess.frame;

import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hrqing.chess.config.props.SystemConfigProps;
import org.hrqing.chess.frame.listener.*;
import org.hrqing.chess.service.GameService;
import org.hrqing.chess.service.LogService;
import org.hrqing.chess.service.PikaFishService;
import org.hrqing.chess.util.ImageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * @author Hrqing
 */
@Slf4j
public class MainFrame extends JFrame implements InitializingBean {

    private final SystemConfigProps systemConfigProps;
    private final LogService logService;
    private final GameService gameService;
    private final PikaFishService pikaFishService;

    public MainFrame(SystemConfigProps systemConfigProps, LogService logService, GameService gameService, PikaFishService pikaFishService) throws HeadlessException {
        this.systemConfigProps = systemConfigProps;
        this.logService = logService;
        this.gameService = gameService;
        this.pikaFishService = pikaFishService;
    }

    private JPanel mainPanel;
    private JPanel northPanel;
    private JPanel platePanel;
    private JPanel plateNorthPanel;
    private JPanel plateSouthPanel;
    private JPanel centerPanel;
    private JPanel eastPanel;
    private JPanel eastNorthPanel;
    private JLabel timeLabel;
    private JPanel southPanel;
    private JLabel southTimeLabel;
    private JLabel executeLabel;
    private JLabel statusLabel;

    private JMenuItem exitMenuItem;
    private JMenuItem newMenuItem;
    private JMenuItem continueMenuItem;

    private JMenuItem revokeMenuItem;
    private JRadioButtonMenuItem easyItem;
    private JRadioButtonMenuItem normalItem;
    private JRadioButtonMenuItem hardItem;

    private static ChessLabel select;

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$() {
        createUIComponents();
        mainPanel.setLayout(new BorderLayout(0, 0));
        mainPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        platePanel.setLayout(new BorderLayout(0, 0));
        mainPanel.add(platePanel, BorderLayout.CENTER);
        platePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        platePanel.add(centerPanel, BorderLayout.CENTER);
        platePanel.add(plateNorthPanel, BorderLayout.NORTH);
        platePanel.add(plateSouthPanel, BorderLayout.SOUTH);
        eastPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
        mainPanel.add(eastPanel, BorderLayout.EAST);
        eastPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        eastNorthPanel = new JPanel();
        eastNorthPanel.setLayout(new BorderLayout(0, 0));
        eastPanel.add(eastNorthPanel);
        timeLabel = new JLabel();
        timeLabel.setText("");
        eastNorthPanel.add(timeLabel, BorderLayout.NORTH);
        mainPanel.add(northPanel, BorderLayout.NORTH);
        northPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), null, TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
        southPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
        mainPanel.add(southPanel, BorderLayout.SOUTH);
        southTimeLabel.setText("");
        southPanel.add(southTimeLabel);
        executeLabel.setText("");
        southPanel.add(executeLabel);
        statusLabel.setText("");
        southPanel.add(statusLabel);
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$() {
        return mainPanel;
    }

    private void createUIComponents() {
        setTitle("中国象棋");
        setSize(930, 945);
        setResizable(false);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        mainPanel = new JPanel();

        platePanel = new JPanel();

        centerPanel = new CenterBackgroundPanel();
        centerPanel.setDoubleBuffered(true);

        plateNorthPanel = new JPanel();
        plateNorthPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
        plateNorthPanel.setPreferredSize(new Dimension(centerPanel.getWidth(), 20));

        JLabel plateNorthLabel = new JLabel();
        plateNorthLabel.setPreferredSize(new Dimension(CenterBackgroundPanel.COLUMN_WIDTH[0], 20));
        plateNorthPanel.add(plateNorthLabel);
        for (int i = 1; i < CenterBackgroundPanel.COLUMN_WIDTH.length; i++) {
            String[] names = CenterBackgroundPanel.COLUMN_NAME[i - 1];
            JButton button = new JButton(names[0]);
            button.setEnabled(false);
            button.setPreferredSize(new Dimension(CenterBackgroundPanel.COLUMN_WIDTH[i], 20));
            plateNorthPanel.add(button);
        }
        platePanel.add(plateNorthPanel, BorderLayout.NORTH);

        plateSouthPanel = new JPanel();
        plateSouthPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
        plateSouthPanel.setPreferredSize(new Dimension(centerPanel.getWidth(), 20));

        JLabel plateSouthLabel = new JLabel();
        plateSouthLabel.setPreferredSize(new Dimension(CenterBackgroundPanel.COLUMN_WIDTH[0], 20));
        plateSouthPanel.add(plateSouthLabel);
        for (int i = 1; i < CenterBackgroundPanel.COLUMN_WIDTH.length; i++) {
            String[] names = CenterBackgroundPanel.COLUMN_NAME[i - 1];
            JButton button = new JButton(names[1]);
            button.setEnabled(false);
            button.setPreferredSize(new Dimension(CenterBackgroundPanel.COLUMN_WIDTH[i], 20));
            plateSouthPanel.add(button);
        }
        platePanel.add(plateSouthPanel, BorderLayout.SOUTH);

        northPanel = new JPanel();
        northPanel.setPreferredSize(new Dimension(platePanel.getWidth(), 25));
        northPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 3, 0));
        JMenuBar menuBar = new JMenuBar();

        JMenu gameMenu = new JMenu("游戏");

        newMenuItem = new JMenuItem("新游戏");
        gameMenu.add(newMenuItem);

        continueMenuItem = new JMenuItem("继续游戏");
        gameMenu.add(continueMenuItem);

        gameMenu.addSeparator();

        exitMenuItem = new JMenuItem("退出");
        gameMenu.add(exitMenuItem);
        menuBar.add(gameMenu);

        JMenu operateMenu = new JMenu("操作");

        JMenu depthMenu = new JMenu("难度选择");
        easyItem = new JRadioButtonMenuItem("简单");
        normalItem = new JRadioButtonMenuItem("正常");
        hardItem = new JRadioButtonMenuItem("困难");
        depthMenu.add(easyItem);
        depthMenu.add(normalItem);
        depthMenu.add(hardItem);
        operateMenu.add(depthMenu);

        operateMenu.addSeparator();

        revokeMenuItem = new JMenuItem("回退");
        operateMenu.add(revokeMenuItem);
        menuBar.add(operateMenu);

        northPanel.add(menuBar);

        eastPanel = new JPanel();
        eastPanel.setPreferredSize(new Dimension(200, platePanel.getHeight()));

        southPanel = new JPanel();
        southPanel.setPreferredSize(new Dimension(0, 25));
        southPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
        southTimeLabel = new JLabel();
        new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String format = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                southTimeLabel.setText(format);
            }
        }).start();
        executeLabel = new JLabel();
        statusLabel = new JLabel();
    }

    @Override
    public void afterPropertiesSet() {
        setContentPane($$$getRootComponent$$$());

        ((CenterBackgroundPanel) centerPanel).setColor(systemConfigProps.getChess().getColor());
        ((CenterBackgroundPanel) centerPanel).setExecuting(systemConfigProps.getChess().getColor());
        ((CenterBackgroundPanel) centerPanel).setDepth(systemConfigProps.getDepth().getDepth());

        switch (systemConfigProps.getDepth().getDepth()) {
            case EASY -> {
                easyItem.setSelected(true);
            }
            case NORMAL -> {
                normalItem.setSelected(true);
            }
            case HARD -> {
                hardItem.setSelected(true);
            }
        }

        CenterBackgroundPanel.ExecuteTime executeTime = new CenterBackgroundPanel.ExecuteTime();
        switch (systemConfigProps.getChess().getColor()) {
            case RED -> {
                executeTime.setRed(System.currentTimeMillis());
                ChessLabel.selected(centerPanel, ChessLabel.Color.RED);
            }
            case BLACK -> {
                executeTime.setBlack(System.currentTimeMillis());
                ChessLabel.selected(centerPanel, ChessLabel.Color.BLACK);
            }
        }
        ((CenterBackgroundPanel) centerPanel).setExecuteTime(executeTime);

        //        ChessLabel.restore((CenterBackgroundPanel) centerPanel);
        LogService.LogInfo topLog = logService.findTopLog();
        if (topLog != null) {
            LogService.loadLogInfo((CenterBackgroundPanel) this.centerPanel, topLog);
        }


        new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ChessLabel.Color executing = ((CenterBackgroundPanel) centerPanel).getExecuting();
                CenterBackgroundPanel.ExecuteTime executeTime = ((CenterBackgroundPanel) centerPanel).getExecuteTime();
                String executingText = "";
                switch (executing) {
                    case ChessLabel.Color.RED -> {
                        executingText += ChessLabel.Color.RED.getSimple() + ":";
                        executingText += (System.currentTimeMillis() - executeTime.getRed()) / 1000;
                    }
                    case ChessLabel.Color.BLACK -> {
                        executingText += ChessLabel.Color.BLACK.getSimple() + ":";
                        executingText += (System.currentTimeMillis() - executeTime.getBlack()) / 1000;
                    }
                }
                executeLabel.setText(executingText);
            }
        }).start();

        centerPanel.addMouseListener(new CenterMouseListener((CenterBackgroundPanel) centerPanel, statusLabel, systemConfigProps, gameService, logService, pikaFishService));
        exitMenuItem.addActionListener(new ExitMenuItemActionListener(this));
        newMenuItem.addActionListener(new NewMenuItemActionListener(this, (CenterBackgroundPanel) centerPanel, systemConfigProps, logService));
        continueMenuItem.addActionListener(new ContinueMenuItemActionListener(this, (CenterBackgroundPanel) centerPanel, systemConfigProps, logService, gameService, pikaFishService));
        revokeMenuItem.addActionListener(new RevokeMenuItemActionListener(this, (CenterBackgroundPanel) centerPanel));

        easyItem.addActionListener(e -> ((CenterBackgroundPanel) centerPanel).setDepth(SystemConfigProps.Depth.EASY));
        normalItem.addActionListener(e -> ((CenterBackgroundPanel) centerPanel).setDepth(SystemConfigProps.Depth.NORMAL));
        hardItem.addActionListener(e -> ((CenterBackgroundPanel) centerPanel).setDepth(SystemConfigProps.Depth.HARD));
    }

    public static void select(ChessLabel label) {
        select = label;
    }

    public static ChessLabel selected() {
        return select;
    }

}
